﻿using System;

namespace DatabaseGroup.SSIS.SourceAdapters.Parser
{
    /// <summary>
    /// Field parsing exceptions
    /// </summary>
    public class FieldParsingException : Exception
    {
        /// <summary>
        /// Initializes a new instance of the FieldParsingException 
        /// class using an exception message
        /// </summary>
        /// <param name="message">The exception message</param>
        public FieldParsingException(string message)
            : base(message)
        {
        }
    }

    /// <summary>
    /// Indicates the buffer used for parsing a row has been overflown
    /// </summary>
    public class ParsingBufferOverflowException : Exception
    {
        /// <summary>
        /// Gets or sets the column at which the overflow occurred
        /// </summary>
        public int ColumnIndex { get; set; }
    }

    /// <summary>
    /// Indicates too many columns in the row 
    /// </summary>
    public class RowColumnNumberOverflow : Exception
    {
    }

    /// <summary>
    /// The various parsing results
    /// </summary>
    internal enum ParsingResult
    {
        /// <summary>
        /// Parsing token was successfully matched
        /// </summary>
        Match,

        /// <summary>
        /// Parsing token failed to be a complete match
        /// </summary>
        Miss,

        /// <summary>
        /// Parsing token was completely matched
        /// </summary>
        Done
    }

    /// <summary>
    /// Defines methods to processing incoming characters and 
    /// determine the parse state to expect
    /// </summary>
    internal interface IParsingState
    {
        /// <summary>
        /// Adds the next parsing state the parser should expect
        /// </summary>
        /// <param name="nextState">The expected state</param>
        void AddNextState(IParsingState nextState);

        /// <summary>
        /// Sets the current error state of the parser
        /// </summary>
        /// <param name="errorState">The error state to set</param>
        void SetErrorState(IParsingState errorState);

        /// <summary>
        /// Processes a single char using a parsing context and returns the result
        /// </summary>
        /// <param name="parsingContext">The parsing context to parse the char under</param>
        /// <param name="nextChar">The char to parse</param>
        /// <returns>The result of parsing the char</returns>
        ParsingResult ProcessCharacter(IParsingContext parsingContext, char nextChar);
    }

    /// <summary>
    /// Specifies the state of a parsing context and provides the ability
    /// to add data to that context
    /// </summary>
    internal interface IParsingContext
    {
        /// <summary>
        /// Gets or sets the current state of the parsing
        /// </summary>
        IParsingState CurrentState { get; set; }

        /// <summary>
        /// Appends a single char to the underlying context data
        /// </summary>
        /// <param name="ch">The char to add</param>
        void Append(char ch);

        /// <summary>
        /// Appends a string to the underlying context data
        /// </summary>
        /// <param name="text">The string of text to add</param>
        void Append(string text);
    }

    /// <summary>
    /// Specifies the column count of the row parsed and
    /// provides a way to add data (char) to that row as it is parsed 
    /// </summary>
    internal interface IRowParsingContext
    {
        /// <summary>
        /// Gets the column count of the row being parsed
        /// </summary>
        int ColumnCount { get; }

        /// <summary>
        /// Appends a single char to the underlying row context data
        /// </summary>
        /// <param name="ch">The char to add</param>
        void Append(char ch);
    }
}
